﻿using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Microsoft.SharePoint;

namespace SecurityParser
{
    public class RoleAssignment : DeployableItem
    {
        [XmlElement("Role")]
        public List<RoleMapping> Roles
        {
            get;
            set;
        }

        [XmlAttribute("loginname")]
        public string LoginName
        {
            get;
            set;
        }

        [XmlAttribute("email")]
        public string EmailAddress
        {
            get;
            set;
        }

        [XmlAttribute("defaultuser")]
        public string DefaultUser
        {
            get;
            set;
        }

        [XmlAttribute("owner")]
        public string Owner
        {
            get;
            set;
        }

        [XmlAttribute("name")]
        public string Name
        {
            get;
            set;
        }

        [XmlAttribute("notes")]
        public string Notes
        {
            get;
            set;
        }

        internal void Apply(ISecurableObject item, SPWeb web)
        {
            //if this item should be depoloyed
            if (this.ShouldDeploy())
            {
                //Get a reference to the SPPrincipal thats represented by this object            
                SPPrincipal principal = GetPrincipal(web);

                //Create a new SPRoleAssignment
                SPRoleAssignment newAssignment = CreateAssignment(principal);

                //Attach the roles to the new assignment
                AttachRoles(web, newAssignment);

                //Add the role assignment to the web
                web.RoleAssignments.Add(newAssignment);
            }
        }

        private SPPrincipal CreateUserGroup(SPWeb web)
        {
            SPPrincipal principal;
            SPMember owner = null;
            SPUser defaultUser = null;

            if (string.IsNullOrEmpty(Owner))
            {
                try
                {
                    owner = web.SiteUsers[Owner];

                }
                catch (Exception)
                {
                    //Owner is not found in users collection. Try cross-site groups   
                    try
                    {
                        owner = web.SiteGroups[Owner];
                    }
                    catch (Exception)
                    {
                        //specified owner does not exist
                    }
                }
            }

            if (owner == null)
            {
                owner = web.Site.Owner;
            }

            if (string.IsNullOrEmpty(DefaultUser))
            {
                try
                {
                    defaultUser = web.SiteUsers[DefaultUser];

                }
                catch (Exception)
                {
                    //specified user does not exist
                }
            }


            web.SiteGroups.Add(this.Name, owner, defaultUser, this.Notes);
            principal = web.SiteGroups[this.Name];

            return principal;
        }

        private void AttachRoles(SPWeb web, SPRoleAssignment newAssignment)
        {
            foreach (RoleMapping role in Roles)
            {
                //Apply the Role Definition
                role.Apply(newAssignment, web);
            }
        }

        private SPRoleAssignment CreateAssignment(SPPrincipal principal)
        {
            SPRoleAssignment newAssignment;

            //if we didn't find an existing principal
            if (principal == null)
            {
                //create a new one
                newAssignment = new SPRoleAssignment(LoginName, EmailAddress, Name, Notes);
            }
            else
            {
                //Use the existing principal
                newAssignment = new SPRoleAssignment(principal);
            }
            return newAssignment;
        }

        private SPPrincipal GetPrincipal(SPWeb web)
        {
            SPPrincipal principal;
            if (!string.IsNullOrEmpty(LoginName))
            {
                //try loginName
                try
                {
                    principal = web.SiteUsers[LoginName];

                }
                catch (Exception)
                {
                    return null;
                }

            }
            else
            {
                try
                {
                    //try name to search SPGroups
                    principal = web.SiteGroups[Name];
                }
                catch (Exception)
                {
                    //The user group does not exist. Groups must be created beforehand
                    principal = CreateUserGroup(web);
                }
            }
            return principal;
        }
    }
}
